fix(ci): stop uv.lock PyPI hashes failing the secret scan - #1159
fix(ci): stop uv.lock PyPI hashes failing the secret scan#1159groupthinking wants to merge 1 commit into
Conversation
`gitleaks (working tree)` failed on every pull request. uv records each artifact as a PyPI download URL whose path embeds the artifact's own content hash, and the segment for parso 0.8.7 has enough length and entropy to match the default `square-access-token` rule. Nothing in a pull request's diff could cause or clear it. Allowlist the pattern by line, anchored on the public PyPI CDN host, rather than excluding the lockfile by path. A path exclusion would also hide a private index URL that embeds credentials inline, which is the case this job exists to catch. Verified with the pinned gitleaks 8.18.4: the working tree now reports no leaks, and a copy of the same offending URL rehosted on `pypi.internal.example.com` is still reported. tests/unit/test_secret_scan_config.py pins the shape of the suppression so it cannot be widened later: lockfiles stay scanned, the regex keeps its host anchor and `/packages/` prefix, `regexTarget` stays `line`, and the workflow keeps loading the config. Fixes #1158 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
Agent Completion Truth Gate: NOT_APPLICABLEEvidence agrees. Machine-readable verdict{
"details": {},
"reasons": [],
"verdict": "not_applicable"
} |
There was a problem hiding this comment.
Pull request overview
Narrows a Gitleaks false-positive suppression for public PyPI artifact hashes while retaining lockfile scanning.
Changes:
- Adds a line-targeted PyPI CDN allowlist.
- Adds regression tests for scan configuration and workflow integration.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
.gitleaks.toml |
Adds the PyPI suppression rule. |
tests/unit/test_secret_scan_config.py |
Adds configuration regression guards. |
| regexes = self.allowlist.get("regexes", []) | ||
| self.assertTrue( | ||
| any("files" in r and "pythonhosted" in r for r in regexes), | ||
| "expected an allowlist regex anchored on files.pythonhosted.org; " | ||
| f"got {regexes!r}", |
| for lockfile in SCANNED_LOCKFILES: | ||
| for pattern in paths: | ||
| self.assertNotIn( | ||
| lockfile, | ||
| pattern, |
| regexTarget = "line" | ||
| regexes = [ |
groupthinking
left a comment
There was a problem hiding this comment.
Review — verified locally at 3bdc33e
The core fix is correct and does what it claims. I checked out this head and confirmed:
tests/unit/test_secret_scan_config.py— 5/5 pass (PYTHONPATH=. python3 -m unittest tests.unit.test_secret_scan_config).- The required
gitleaks (working tree)check is green on this head, alongside CodeQL, Trivy, bandit, python-safety, npm-audit, and both Security Scans. The only red status is a manually-canceled Vercel deployment (Canceled from the Vercel Dashboard) — infra noise, not this diff. The two redAgent completion enforcementruns are the repo-wide governance tooling that is failing across many PRs, not something in this change.
I could not re-run gitleaks 8.18.4 here (not installed in this sandbox), so I'm relying on the before/after + mutation evidence in the description for the scanner behavior itself, which is thorough.
The pattern-anchored-not-path-anchored decision is the right call, and the rationale in the description (a private index URL with inline credentials is exactly the secret this job should still catch) is exactly right.
On the three Copilot comments — all three are valid; I confirmed each against the code
-
.gitleaks.toml:12(most important).regexTarget = "line"on the top-level[allowlist]applies to every rule, so any finding on a line containingfiles.pythonhosted.org/packages/is suppressed — not justsquare-access-token. In a committeduv.lockthe practical blast radius is small (each line is a single artifact URL), but it is a genuine widening of a security control: a real token sharing a line with that URL would be hidden. Worth either scoping the exception to thesquare-access-tokenrule (noting the 8.18.4 single-[allowlist]constraint you already documented — rule-scoping needs[[rules.allowlists]], which is more involved) or consciously accepting the residual risk with a one-line note in the config comment so the decision is explicit. -
test_secret_scan_config.py:63—assertNotIn("uv.lock", pattern)is a substring check, so a regex path exclusion like.*\.lock$or^uv[.]lock$would excludeuv.lockwhile sailing past this guard. Compile eachpathsentry and assert it does not match each protected filename. -
test_secret_scan_config.py:75— the host-anchor test asserts substrings are present in the regex, not that the regex rejects a foreign host. An alternation that also permits another host would still pass. Exercise the configured regex against both the public URL and an identical private-host URL so that widening the suppression fails the suite.
None of these blocks the immediate goal (unblocking the repo-wide red secret scan), but 2 and 3 are cheap and directly strengthen the guardrails this PR is built around, and 1 is a real scope question on a security control.
Recommendation
Mergeable as-is to unblock the scan; I'd fold in the two test-hardening fixes (2, 3) and make an explicit accept/scope decision on (1) before or right after merge. Merge itself targets protected main and is left for human sign-off — I'm not auto-merging, and I did not push to this branch (it isn't my designated working branch).
Generated by Claude Code
|
Automated PR-remediation run — terminal state: The gitleaks fix itself is verified: Three governance checks were red on open. I remediated the two that were body-structure failures by restructuring the PR description into the canonical
The remaining failure is not fixable by editing this PR. No merge was performed: protected Generated by Claude Code |
|
Blocker-watch reconciliation at exact head This PR is a competing implementation of the existing canonical Gitleaks repair in #1142 at exact head Why #1142 remains canonical:
Why this PR cannot advance:
The PR is closed unmerged as a duplicate. The branch is preserved; no commit or branch was deleted. |
Canonical issue
Fixes #1158
Outcome
The
Secret Scan / gitleaks (working tree)job stops failing on every pullrequest in the repository.
gitleaksflags one line ofuv.lockthat contains no secret:That string is the PyPI content-hash path segment of the
parso 0.8.7sdist URL.It is high-entropy by construction and matches the
square-access-tokenpattern by coincidence. Because
uv.lockis committed and unrelated to anyindividual change, every PR inherits the failure — the job has been red
repo-wide, which is the worst possible state for a secret scanner: a check
nobody can distinguish a real finding in.
After this change the scan reports
no leaks foundon a clean tree, so afuture red result is signal again.
Scope
.gitleaks.toml, and a testthat pins the properties which make it narrow.
uv.lockitself (unchanged), the gitleaks version pin,.github/workflows/secret-scan.yml, and the default rule set —useDefaultstays on.
What was deliberately not done: the obvious fix is
paths = ['''uv\.lock''']. That is wrong. A uv lockfile can legitimately carrya private index URL with inline credentials
(
https://user:token@pypi.internal/simple/...), which is exactly the leak thisjob exists to catch. Excluding the file by path would blind the scanner to the
one real secret it is most likely to find there. The allowlist is therefore
anchored to the benign pattern instead of to the file.
Risk
matters more than the size of the diff.
properties bound it, and both are asserted by tests: the regex is anchored to
the literal host
https://files\.pythonhosted\.org/packages/, so it cannotmatch a credential on any other host; and it is a
regexesentry, not apathsentry, so no file is ever wholly exempt.which is to say, red on every PR again.
Note on gitleaks semantics that shaped the implementation:
[allowlist]block.
[[allowlists]]withcondition = "AND"arrived in 8.19.pathsandregexesare therefore OR-ed and cannot be AND-combined, which is a second,independent reason the entry had to be pattern-anchored rather than
path-plus-pattern.
regexTarget = "line"is load-bearing. The extracted secret is the bare hexsegment and contains no host at all, so a host-anchored regex only matches
when evaluated against the whole source line. Without it the allowlist
silently does nothing.
Verification
Reproduced and verified with the same gitleaks version CI pins, 8.18.4,
installed locally, using the same command as the workflow
(
gitleaks detect --no-git --config .gitleaks.toml --redact --verbose --exit-code 1):Negative test — the part that matters. A suppression that merely makes the
scan green is worthless. To prove the allowlist is scoped to the benign pattern
and not to the file, the offending line was duplicated into
uv.lockwith thehost swapped to
pypi.internal.example.com:The scanner still catches a same-shaped, high-entropy string on a different
host inside the very file being allowlisted. That is the property that would
have been destroyed by a path exclusion.
tests/unit/test_secret_scan_config.py— 5/5 pass(
PYTHONPATH=. python3 -m unittest tests.unit.test_secret_scan_config). Itasserts:
useDefaultremains enabled; no lockfile is path-allowlisted; theregex retains both the host anchor and the
/packages/prefix;regexTargetis
line; andsecret-scan.ymlstill passes--config .gitleaks.tomlso theconfig is actually consulted.
Mutation-tested three ways, each applied, run, and reverted:
gitleaks (working tree)andagent-completion/truth-gateboth pass on this headAgent completion enforcementis red here, as it is on every open PR in therepository, because its trust policy is unprovisioned. Surveyed and tracked
separately in #1160; it is unrelated to this diff.
Production evidence
Not applicable: no runtime surface changes. The diff is one CI configuration
file plus its test; no application code, dependency, or infrastructure is
touched, and
uv.lockis byte-identical.The evidence for a scanner change is the scanner's own behaviour, which is why
verification above is a real 8.18.4 run at the pinned version rather than a
reimplementation of the rule, and why it includes a negative case proving the
suppression still fails closed on a different host.
Notes for reviewers
Recommend merging this first of the currently open fixes. It unblocks the
secret scan for every PR in the repository, including #1154 and #1155, which are
cut from a
mainthat predates it and stay red on this check until it lands.Agent handoff